#pragma once
#include "OpenGLMacros.h"
#include "stdafx.h"
#include "OpenGL.h"
#include "OpenGL.h"
#include "gl\gl.h"
#include "gl\glu.h"
#include <WinDef.h>

class Transformation {
	public : 
		virtual const Transformation* apply( int axis, float deltaX, float deltaY ) = 0;
		virtual Transformation* updateSensitivity( float sensitivity ) {
			m_sensitivity = sensitivity;
			return this;
		}
	protected:
		float m_sensitivity;
};

class FreeRotation : public Transformation {
	public:
		FreeRotation( void) : m_activeX( AXIS_Y ), m_activeY( AXIS_X ), m_sumDeltaX( 0 ), m_sumDeltaY( 0 ) { }
		virtual const Transformation* apply( int axis, float deltaX, float deltaY ) {
			deltaX *= m_sensitivity;
            int oldActiveX = m_activeX;
            int oldActiveY = m_activeY;
            m_sumDeltaX += deltaX;
			glRotatef( deltaX,
			            (GLfloat)(ACT_ALONG_X(m_activeY)),
						(GLfloat)(ACT_ALONG_Y(m_activeY)),
						(GLfloat)(ACT_ALONG_Z(m_activeY)) );
			if ( abs(m_sumDeltaX) >= 90) {
				m_sumDeltaX = 0;
				m_activeX = (~oldActiveX & 7) ^ oldActiveX ^ oldActiveY;
			}

			deltaY *= m_sensitivity;
			m_sumDeltaY += deltaY;
			glRotatef( deltaY,
						(GLfloat)(ACT_ALONG_X(m_activeX)),
						(GLfloat)(ACT_ALONG_Y(m_activeX)),
						(GLfloat)(ACT_ALONG_Z(m_activeX)) );
			if ( abs( m_sumDeltaY) >= 90) {
				m_sumDeltaY = 0;
				m_activeY = (~oldActiveY & 7) ^ oldActiveY ^ oldActiveX;
			}
			return this;
		}
	private:

		int m_activeX;
		int m_activeY;
		float m_sumDeltaX;
		float m_sumDeltaY;
};

class Rotation : public Transformation {
public:
    virtual const Transformation* apply( int axis, float deltaX, float deltaY) {
        float delta = deltaX + deltaY;  // was int ???
        delta *= m_sensitivity;
        glRotatef( delta,
            (GLfloat)(ACT_ALONG_X(axis)),
            (GLfloat)(ACT_ALONG_Y(axis)),
            (GLfloat)(ACT_ALONG_Z(axis)) );
        return this;
    }
    private:

};


class Translate : public Transformation {
	public:
		virtual const Transformation* apply( int axis, float deltaX, float deltaY) {
			deltaX *= m_sensitivity;
			glTranslatef( deltaX*(ACT_ALONG_X(axis)), deltaX*(ACT_ALONG_Y(axis)), deltaX*(ACT_ALONG_Z(axis)) );
			return this;
		}
};

class Scale : public Transformation {
	public:
		virtual const Transformation* apply( int axis, float deltaX, float deltaY) {
			deltaX *= m_sensitivity;
			glScalef( max(1e-3f, 1+deltaX*(ACT_ALONG_X(axis))),
					  max(1e-3f, 1+deltaX*(ACT_ALONG_Y(axis))),
					  max(1e-3f, 1+deltaX*(ACT_ALONG_Z(axis))) );
			return this;
		}
};